package com.bytecamp.testplatform.service.impl;

import com.alibaba.fastjson2.JSON;
import com.bytecamp.testplatform.dto.TestCaseDTO;
import com.bytecamp.testplatform.mapper.ApiInfoMapper;
import com.bytecamp.testplatform.mapper.TestCaseMapper;
import com.bytecamp.testplatform.model.ApiInfo;
import com.bytecamp.testplatform.model.TestCase;
import com.bytecamp.testplatform.service.TestCaseService;
import com.bytecamp.testplatform.util.AiClientUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service
@RequiredArgsConstructor
@Slf4j
public class TestCaseServiceImpl implements TestCaseService {

    private final ApiInfoMapper apiInfoMapper;
    private final TestCaseMapper testCaseMapper;
    private final AiClientUtil aiClientUtil;

    // TestCaseServiceImpl.java
    @Override
    public List<TestCase> getCaseList(Long apiId) {
        if (apiId == null) {
            return testCaseMapper.selectAll(); // 查询所有用例
        } else {
            return testCaseMapper.selectByApiId(apiId); // 查询指定接口的用例
        }
    }


    @Override
    public String generateAndSave(Long apiId) {
        // 1. 查询接口元数据
        ApiInfo apiInfo = apiInfoMapper.selectById(apiId);
        if (apiInfo == null) {
            return "接口不存在（apiId=" + apiId + "）";
        }

        // 2. 构建更清晰的Prompt（提高AI生成质量）
        String prompt = buildPrompt(apiInfo);

        // 3. 调用豆包API（使用注入的工具类）
        String aiResponse;
        try {
            aiResponse = aiClientUtil.generateCasesByDoubao(prompt);
        } catch (Exception e) {
            return "AI生成失败：" + e.getMessage();
        }

        // 4. 解析AI响应（保持原逻辑，若AI返回格式有变化需调整）
        List<TestCaseDTO> caseDTOs = parseAiResponse(aiResponse);
        if (caseDTOs.isEmpty()) {
            return "未解析到有效用例，请检查Prompt或API响应格式";
        }

        // 5. 保存用例
        List<TestCase> testCases = convertToTestCase(caseDTOs, apiId);
        int insertCount = testCaseMapper.batchInsert(testCases);
        return "生成成功，共" + insertCount + "个用例（接口：" + apiInfo.getPath() + "）";
    }

    // 优化Prompt（更明确的格式要求，减少AI误解）
    private String buildPrompt(ApiInfo apiInfo) {
        return "请为以下接口生成测试用例，严格按照格式要求输出：\n" +
                "【接口信息】\n" +
                "路径：" + apiInfo.getPath() + "\n" +
                "方法：" + apiInfo.getMethod() + "\n" +
                "参数：" + apiInfo.getRequestParams() + "\n" +
                "【生成要求】\n" +
                "1. 覆盖场景：正常参数（必填项齐全）、参数缺失（如少传pageNum）、参数格式错误（如页码为字符串）、边界值（如pageSize=0或1000）。\n" +
                "2. 每个用例格式：\n" +
                "用例名称：[场景描述]\n" +
                "请求参数：[JSON格式，包含所有参数，示例：{\"pageNum\":1, \"pageSize\":10}]\n" +
                "预期响应：[JSON格式，包含code和关键结果，示例：{\"code\":0, \"msg\":\"成功\"}]\n" +
                "3. 用例之间用---分隔，不要其他说明文字。\n" +
                "4. 至少生成5个用例。";
    }

    /**
     * 解析AI返回的用例文本（适配实际响应格式）
     */
    private List<TestCaseDTO> parseAiResponse(String aiResponse) {
        List<TestCaseDTO> caseDTOs = new ArrayList<>();
        if (aiResponse == null || aiResponse.trim().isEmpty()) {
            return caseDTOs;
        }

        // 1. 按---分割单个用例（处理可能的前后空格和换行）
        String[] caseTexts = aiResponse.split("\\s*---\\s*");

        // 2. 正则表达式匹配单个用例的三部分内容
        // 格式：用例名称：xxx\n请求参数：xxx\n预期响应：xxx
        Pattern pattern = Pattern.compile(
                "用例名称：(.*?)\n" +          // 匹配用例名称（非贪婪模式）
                        "请求参数：(.*?)\n" +          // 匹配请求参数
                        "预期响应：(.*?)(\n|$)",       // 匹配预期响应（直到换行或结束）
                Pattern.DOTALL                 // 允许.匹配换行符
        );

        for (String text : caseTexts) {
            String trimmedText = text.trim();
            if (trimmedText.isEmpty()) {
                continue; // 跳过空字符串（可能因分割产生）
            }

            Matcher matcher = pattern.matcher(trimmedText);
            if (matcher.find()) {
                // 提取三部分内容（去除首尾空格）
                String caseName = matcher.group(1).trim();
                String requestData = matcher.group(2).trim();
                String expectedResult = matcher.group(3).trim();

                // 验证请求参数和预期响应是否为合法JSON（避免存入无效数据）
                if (isValidJson(requestData) && isValidJson(expectedResult)) {
                    TestCaseDTO dto = new TestCaseDTO();
                    dto.setCaseName(caseName);
                    dto.setRequestData(requestData);
                    dto.setExpectedResult(expectedResult);
                    dto.setPriority(getPriority(caseName)); // 根据用例名称推断优先级
                    caseDTOs.add(dto);
                } else {
                    log.warn("用例[{}]的JSON格式无效，已跳过", caseName);
                }
            } else {
                log.warn("无法解析用例文本：{}", trimmedText);
            }
        }

        return caseDTOs;
    }

    /**
     * 验证字符串是否为合法JSON
     */
    private boolean isValidJson(String jsonStr) {
        try {
            JSON.parseObject(jsonStr); // 尝试解析为JSON对象
            return true;
        } catch (Exception e) {
            try {
                JSON.parseArray(jsonStr); // 尝试解析为JSON数组
                return true;
            } catch (Exception ex) {
                return false;
            }
        }
    }

    /**
     * 根据用例名称推断优先级（1-高，2-中，3-低）
     */
    private Integer getPriority(String caseName) {
        if (caseName.contains("正常参数") || caseName.contains("必填项")) {
            return 1; // 核心场景：高优先级
        } else if (caseName.contains("边界值") || caseName.contains("格式错误")) {
            return 2; // 次核心场景：中优先级
        } else {
            return 3; // 其他场景：低优先级
        }
    }

    /**
     * 转换DTO为数据库实体
     */
    private List<TestCase> convertToTestCase(List<TestCaseDTO> dtos, Long apiId) {
        List<TestCase> testCases = new ArrayList<>();
        for (TestCaseDTO dto : dtos) {
            TestCase testCase = new TestCase();
            testCase.setApiId(apiId);
            testCase.setCaseName(dto.getCaseName());
            testCase.setRequestData(dto.getRequestData());
            testCase.setExpectedResult(dto.getExpectedResult());
            testCase.setPriority(dto.getPriority());
            testCase.setStatus(0); // 0-未执行
            testCases.add(testCase);
        }
        return testCases;
    }
}
